//
// Created by YE on 2024/1/17.
//
#include "coder.h"
#include "../vm/CFunction.h"
#include "../vm/memory.h"

#define IF_JUDGE true
#define WHILE_JUDGE false

Sem_State operate(Parser *p, T ac) {
    switch (ac) {
        case AC_SET_EKIND:
            return ac_set_ekind(&p->cs, &p->current_token);
        case AC_MALLOC_VAR:
            return ac_malloc_var(p);
        case AC_PUSH_CONST:
            return ac_push_const(&p->cs, &p->sem, &p->current_token);
        case AC_ASSIGN_FIRST:
            return gen_assign_first_code(&p->cs, &p->sem);
        case AC_ADD:
            return ac_double_compute(&p->cs, &p->sem, OP_ADD);
        case AC_SUB:
            return ac_double_compute(&p->cs, &p->sem, OP_SUB);
        case AC_MUL:
            return ac_double_compute(&p->cs, &p->sem, OP_MUL);
        case AC_DIV:
            return ac_double_compute(&p->cs, &p->sem, OP_DIV);
        case AC_INNER:
            return ac_inner(&p->cs, &p->sem);
        case AC_LESS:
            return ac_double_compute(&p->cs, &p->sem, OP_LESS);
        case AC_GREATER:
            return ac_double_compute(&p->cs, &p->sem, OP_GREATER);
        case AC_LESSEQUAL:
            return ac_double_compute(&p->cs, &p->sem, OP_LESSEQUAL);
        case AC_GREATEREQUAL:
            return ac_double_compute(&p->cs, &p->sem, OP_GREATEREQUAL);
        case AC_EQUAL:
            return ac_double_compute(&p->cs, &p->sem, OP_EQUAL);
        case AC_NOTEQUAL:
            return ac_double_compute(&p->cs, &p->sem, OP_NOTEQUAL);
        case AC_AND:
            return ac_double_compute(&p->cs, &p->sem, OP_AND);
        case AC_OR:
            return ac_double_compute(&p->cs, &p->sem, OP_OR);
        case AC_NOT:
            return ac_not(&p->cs, &p->sem);
        case AC_NEG:
            return ac_neg(&p->cs, &p->sem);
        case AC_POW:
            return ac_double_compute(&p->cs, &p->sem, OP_POW);
        case AC_MOD:
            return ac_double_compute(&p->cs, &p->sem, OP_MOD);
        case AC_SEM_PUSH_VAR:
            return ac_sem_push_var(p);
        case AC_SEM_PUSH_FUNC:
            return ac_push_func(&p->cs, &p->sem, &p->current_token);
        case AC_SEM_POP:
            return ac_sem_pop(&p->cs, &p->sem);
        case AC_POP:
            return ac_pop(&p->cs, &p->sem);
        case AC_SEM_ASSIGN_END:
            return ac_assign_end(&p->cs, &p->sem);
        case AC_PUSH_ASSIGN:
            return ac_push_assign(&p->cs, &p->sem);
        case AC_PUSH_WHILE:
            return ac_push_while(&p->cs, &p->sem);
        case AC_IF_JUDGE:
            return ac_judge(&p->cs, &p->sem, &p->if_sem, IF_JUDGE);
        case AC_WHILE_JUDGE:
            return ac_judge(&p->cs, &p->sem, &p->if_sem, WHILE_JUDGE);
        case AC_WHILE_END:
            return ac_while_end(&p->cs, &p->sem);
        case AC_BREAK:
            return ac_while_break(&p->cs, &p->sem);
        case AC_IF_END:
            return ac_if_end(&p->cs, &p->if_sem);
        case AC_PUSH_ELSE:
            return ac_push_else(&p->cs, &p->if_sem);
        case AC_ELSE_END:
            return ac_else_end(&p->cs, &p->if_sem);
        case AC_FUNC_COUNT_PARAM:
            return ac_func_count(&p->cs, &p->sem);
        case AC_FUNC_END:
            return ac_func_end(&p->cs, &p->sem);
        case AC_DEF_FUNC_START:
            return ac_def_func_start(&p->cs, &p->sem, &p->current_token);
        case AC_DEF_COUNT_PARAMS:
            return ac_def_count_params(p);
        case AC_RETURN:
            return ac_return(&p->cs, &p->sem);
        case AC_DEF_FUNC_END:
            return ac_def_func_end(&p->cs, &p->sem);
        case AC_MAT_COUNT_ROW:
            return ac_mat_count_row(p);
        case AC_MAT_COUNT_COL:
            return ac_mat_count_col(p);
        case AC_MAT_START:
            return ac_mat_start(p);
        case AC_MAT_END:
            return ac_mat_end(p);
        case AC_INDEX:
            return ac_index(p);
        default:
            return SEM_ERROR;
    }
}

static void code_op(CState *cs, unsigned int opcode) {
    if (cs->declare_func) {
        if (cs->vm_i_f_p >= YCH_VM_INSTRUCTION_SIZE)return;
        VM_I[cs->vm_i_f_p++] = opcode;
    } else {
        if (cs->vm_i_p >= YCH_VM_FUNC_START)return;
        VM_I[cs->vm_i_p++] = opcode;
    }
}

static void code_ABC(CState *cs, unsigned int opcode, unsigned int a, unsigned int b, unsigned int c) {
    if (cs->declare_func) {
        if (cs->vm_i_f_p >= YCH_VM_INSTRUCTION_SIZE)return;
        VM_I[cs->vm_i_f_p++] = (c << OFFSET_C) | (b << OFFSET_B) | (a << OFFSET_A) | opcode;
    } else {
        if (cs->vm_i_p >= YCH_VM_FUNC_START)return;
        VM_I[cs->vm_i_p++] = (c << OFFSET_C) | (b << OFFSET_B) | (a << OFFSET_A) | opcode;
    }
}

static void code_ABx(CState *cs, unsigned int opcode, unsigned int a, unsigned int bx) {
    if (cs->declare_func) {
        if (cs->vm_i_f_p >= YCH_VM_INSTRUCTION_SIZE)return;
        VM_I[cs->vm_i_f_p++] = (bx << OFFSET_B) | (a << OFFSET_A) | opcode;
    } else {
        if (cs->vm_i_p >= YCH_VM_FUNC_START)return;
        VM_I[cs->vm_i_p++] = (bx << OFFSET_B) | (a << OFFSET_A) | opcode;
    }
}

static Sem_State ac_neg(CState *cs, Sen_Stack *sem) {
    MInfo &m1 = sem->back();
    switch (m1.mt) {
        case MT_INT_CONST:
            m1.v.i = -m1.v.i;
            return SEM_OK;
        case MT_FLOAT_CONST:
            m1.v.f = -m1.v.f;
            return SEM_OK;
        case MT_VAR:
            if (cs->declare_func) {
                code_ABx(cs, OP_MOV, 0, m1.v.p);
            } else {
                code_ABx(cs, OP_LOAD_M, 0, m1.v.p);
            }
            code_ABC(cs, OP_NEG, 0, 0, 0);
            m1.mt = MT_T;
            return SEM_OK;
        case MT_T:
            code_ABx(cs, OP_LOAD_S, 0, 0);
            code_ABC(cs, OP_NEG, 0, 0, 0);
            m1.mt = MT_T;
            return SEM_OK;
    }
    return SEM_ERROR;
}

static Sem_State ac_not(CState *cs, Sen_Stack *sem) {
    MInfo &m1 = sem->back();
    switch (m1.mt) {
        case MT_BOOL_CONST:
            m1.v.b = !m1.v.b;
            return SEM_OK;
        case MT_VAR:
            if (cs->declare_func) {
                code_ABx(cs, OP_MOV, 0, m1.v.p);
            } else {
                code_ABx(cs, OP_LOAD_M, 0, m1.v.p);
            }
            code_ABC(cs, OP_NOT, 0, 0, 0);
            m1.mt = MT_T;
            return SEM_OK;
        case MT_T:
            code_ABx(cs, OP_LOAD_S, 0, 0);
            code_ABC(cs, OP_NOT, 0, 0, 0);
            m1.mt = MT_T;
            return SEM_OK;
    }
    return SEM_ERROR;
}

static Sem_State ac_assign(CState *cs, Sen_Stack *sem) {
    //TODO ASSIGN
    OP op = OP_STORE_M;
    unsigned int p;
    while (sem->back().mt == MT_ASSIGN) {
        sem->pop_back();
        MInfo m2 = sem->back();
        sem->pop_back();
        MInfo m1;
        if (sem->back().mt == MT_ASSIGN) {
            m1 = sem->operator[](sem->size() - 2);
        } else {
            m1 = sem->back();
            sem->back().mt = MT_T;
            op = OP_ASSIGN;
        }
        if (m1.mt == MT_VAR) {
            switch (m2.mt) {
                case MT_VAR:
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 1, m2.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 0, m2.v.p);
                    }
                    code_ABx(cs, op, cs->declare_func, m1.v.p);
                    break;
                case MT_T:
                    code_ABx(cs, OP_LOAD_S, cs->declare_func, 0);
                    code_ABx(cs, op, cs->declare_func, m1.v.p);
                    break;
                case MT_INT_CONST:
                    if (find_and_alloc_int(cs, m2.v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
                    code_ABx(cs, OP_LOAD_I, cs->declare_func, p);
                    code_ABx(cs, op, cs->declare_func, m1.v.p);
                    break;
                case MT_FLOAT_CONST:
                    if (find_and_alloc_float(cs, m2.v.f, &p))return SEM_MEM_OVERFLOW_ERROR;
                    code_ABx(cs, OP_LOAD_F, cs->declare_func, p);
                    code_ABx(cs, op, cs->declare_func, m1.v.p);
                    break;
                case MT_BOOL_CONST:
                    code_ABx(cs, OP_LOAD_B, cs->declare_func, m2.v.b);
                    code_ABx(cs, op, cs->declare_func, m1.v.p);
                    break;
            }
        } else {
            return SEM_ERROR;
        }
    }
    return SEM_OK;
}

static Sem_State ac_inner(CState *cs, Sen_Stack *sem) {
    unsigned int p;
    MInfo m2 = sem->back();
    sem->pop_back();
    MInfo &m1 = sem->back();
    if (m1.mt == MT_VAR) {
        if (cs->declare_func) {
            code_ABx(cs, OP_MOV, 0, m1.v.p);
        } else {
            code_ABx(cs, OP_LOAD_M, 0, m1.v.p);
        }
    } else if (m1.mt == MT_T) {
        code_ABx(cs, OP_LOAD_S, 0, 0);
    } else return SEM_ERROR;
    if (m2.mt == MT_VAR) {
        if (cs->declare_func) {
            code_ABx(cs, OP_MOV, 1, m2.v.p);
        } else {
            code_ABx(cs, OP_LOAD_M, 1, m2.v.p);
        }
    } else if (m2.mt == MT_T) {
        code_ABx(cs, OP_LOAD_S, 1, 0);
    } else return SEM_ERROR;
    code_ABC(cs, OP_IMUL, 0, 0, 1);
    m1.mt = MT_T;
    return SEM_OK;
}

static Sem_State ac_double_compute(CState *cs, Sen_Stack *sem, OP op) {
    unsigned int p;
    MInfo m2 = sem->back();
    sem->pop_back();
    MInfo &m1 = sem->back();
    switch (m1.mt) {
        case MT_VAR:
            switch (m2.mt) {
                case MT_VAR:
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 0, m1.v.p);
                        code_ABx(cs, OP_MOV, 1, m2.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 0, m1.v.p);
                        code_ABx(cs, OP_LOAD_M, 1, m2.v.p);
                    }
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_T:
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 0, m1.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 0, m1.v.p);
                    }
                    code_ABx(cs, OP_LOAD_S, 1, 0);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_INT_CONST:
                    if (find_and_alloc_int(cs, m2.v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 0, m1.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 0, m1.v.p);
                    }
                    code_ABx(cs, OP_LOAD_I, 1, p);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_FLOAT_CONST:
                    if (find_and_alloc_float(cs, m2.v.f, &p))return SEM_MEM_OVERFLOW_ERROR;
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 0, m1.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 0, m1.v.p);
                    }
                    code_ABx(cs, OP_LOAD_F, 1, p);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_BOOL_CONST:
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 0, m1.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 0, m1.v.p);
                    }
                    code_ABx(cs, OP_LOAD_B, 1, m2.v.b);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
            }
            break;
        case MT_T:
            switch (m2.mt) {
                case MT_VAR:
                    code_ABx(cs, OP_LOAD_S, 0, 0);
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 1, m2.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 1, m2.v.p);
                    }
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_T:
                    code_ABx(cs, OP_LOAD_S, 0, 0);
                    code_ABx(cs, OP_LOAD_S, 1, 0);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_INT_CONST:
                    if (find_and_alloc_int(cs, m2.v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
                    code_ABx(cs, OP_LOAD_S, 0, 0);
                    code_ABx(cs, OP_LOAD_I, 1, p);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_FLOAT_CONST:
                    if (find_and_alloc_float(cs, m2.v.f, &p))return SEM_MEM_OVERFLOW_ERROR;
                    code_ABx(cs, OP_LOAD_S, 0, 0);
                    code_ABx(cs, OP_LOAD_F, 1, p);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_BOOL_CONST:
                    code_ABx(cs, OP_LOAD_S, 0, 0);
                    code_ABx(cs, OP_LOAD_B, 1, m2.v.b);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
            }
            break;
        case MT_INT_CONST:
            switch (m2.mt) {
                case MT_VAR:
                    if (find_and_alloc_int(cs, m1.v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
                    code_ABx(cs, OP_LOAD_I, 0, p);
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 1, m2.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 1, m2.v.p);
                    }
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_T:
                    if (find_and_alloc_int(cs, m1.v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
                    code_ABx(cs, OP_LOAD_I, 0, p);
                    code_ABx(cs, OP_LOAD_S, 1, 0);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_INT_CONST:
                    switch (op) {
                        case OP_ADD:
                            m1.v.i += m2.v.i;
                            break;
                        case OP_SUB:
                            m1.v.i -= m2.v.i;
                            break;
                        case OP_MUL:
                            m1.v.i *= m2.v.i;
                            break;
                        case OP_DIV:
                            m1.v.i /= m2.v.i;
                            break;
                        case OP_LESS:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i < m2.v.i;
                            break;
                        case OP_GREATER:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i > m2.v.i;
                            break;
                        case OP_LESSEQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i <= m2.v.i;
                            break;
                        case OP_GREATEREQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i >= m2.v.i;
                            break;
                        case OP_EQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i == m2.v.i;
                            break;
                        case OP_NOTEQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i != m2.v.i;
                            break;
                        case OP_POW:
                            m1.v.i = pow(m1.v.i, m2.v.i);
                            break;
                        case OP_MOD:
                            m1.v.i %= m2.v.i;
                            break;
                        default:
                            return SEM_ERROR;
                    }
                    return SEM_OK;
                case MT_FLOAT_CONST:
                    m1.mt = MT_FLOAT_CONST;
                    switch (op) {
                        case OP_ADD:
                            m1.v.f = m1.v.i + m2.v.f;
                            break;
                        case OP_SUB:
                            m1.v.f = m1.v.i - m2.v.f;
                            break;
                        case OP_MUL:
                            m1.v.f = m1.v.i * m2.v.f;
                            break;
                        case OP_DIV:
                            m1.v.f = m1.v.i / m2.v.f;
                            break;
                        case OP_LESS:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i < m2.v.f;
                            break;
                        case OP_GREATER:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i > m2.v.f;
                            break;
                        case OP_LESSEQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i <= m2.v.f;
                            break;
                        case OP_GREATEREQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i >= m2.v.f;
                            break;
                        case OP_EQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i == m2.v.f;
                            break;
                        case OP_NOTEQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.i != m2.v.f;
                            break;
                        case OP_POW:
                            m1.v.f = pow(m1.v.i, m2.v.f);
                            break;
                        default:
                            return SEM_ERROR;
                    }
                    return SEM_OK;
            }
            break;
        case MT_FLOAT_CONST:
            switch (m2.mt) {
                case MT_VAR:
                    if (find_and_alloc_float(cs, m1.v.f, &p))return SEM_MEM_OVERFLOW_ERROR;
                    code_ABx(cs, OP_LOAD_F, 0, p);
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 1, m2.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 1, m2.v.p);
                    }
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_T:
                    if (find_and_alloc_float(cs, m1.v.f, &p))return SEM_MEM_OVERFLOW_ERROR;
                    code_ABx(cs, OP_LOAD_F, 0, p);
                    code_ABx(cs, OP_LOAD_S, 1, 0);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_INT_CONST:
                    switch (op) {
                        case OP_ADD:
                            m1.v.f += m2.v.i;
                            break;
                        case OP_SUB:
                            m1.v.f -= m2.v.i;
                            break;
                        case OP_MUL:
                            m1.v.f *= m2.v.i;
                            break;
                        case OP_DIV:
                            m1.v.f /= m2.v.i;
                            break;
                        case OP_LESS:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f < m2.v.i;
                            break;
                        case OP_GREATER:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f > m2.v.i;
                            break;
                        case OP_LESSEQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f <= m2.v.i;
                            break;
                        case OP_GREATEREQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f >= m2.v.i;
                            break;
                        case OP_EQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f == m2.v.i;
                            break;
                        case OP_NOTEQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f != m2.v.i;
                            break;
                        case OP_POW:
                            m1.v.f = pow(m1.v.f, m2.v.i);
                            break;
                        default:
                            return SEM_ERROR;
                    }
                    return SEM_OK;
                case MT_FLOAT_CONST:
                    switch (op) {
                        case OP_ADD:
                            m1.v.f += m2.v.f;
                            break;
                        case OP_SUB:
                            m1.v.f -= m2.v.f;
                            break;
                        case OP_MUL:
                            m1.v.f *= m2.v.f;
                            break;
                        case OP_DIV:
                            m1.v.f /= m2.v.f;
                            break;
                        case OP_LESS:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f < m2.v.f;
                            break;
                        case OP_GREATER:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f > m2.v.f;
                            break;
                        case OP_LESSEQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f <= m2.v.f;
                            break;
                        case OP_GREATEREQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f >= m2.v.f;
                            break;
                        case OP_EQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f == m2.v.f;
                            break;
                        case OP_NOTEQUAL:
                            m1.mt = MT_BOOL_CONST;
                            m1.v.b = m1.v.f != m2.v.f;
                            break;
                        case OP_POW:
                            m1.v.f = pow(m1.v.f, m2.v.f);
                            break;
                        default:
                            return SEM_ERROR;
                    }
                    return SEM_OK;
            }
            break;
        case MT_BOOL_CONST:
            switch (m2.mt) {
                case MT_VAR:
                    code_ABx(cs, OP_LOAD_B, 0, m1.v.b);
                    if (cs->declare_func) {
                        code_ABx(cs, OP_MOV, 1, m2.v.p);
                    } else {
                        code_ABx(cs, OP_LOAD_M, 1, m2.v.p);
                    }
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_T:
                    code_ABx(cs, OP_LOAD_B, 0, m1.v.b);
                    code_ABx(cs, OP_LOAD_S, 1, 0);
                    code_ABC(cs, op, 0, 0, 1);
                    m1.mt = MT_T;
                    return SEM_OK;
                case MT_BOOL_CONST:
                    switch (op) {
                        case OP_EQUAL:
                            m1.v.b = m1.v.b == m2.v.b;
                            break;
                        case OP_NOTEQUAL:
                            m1.v.b = m1.v.b != m2.v.b;
                            break;
                        case OP_AND:
                            m1.v.b &= m2.v.b;
                            break;
                        case OP_OR:
                            m1.v.b |= m2.v.b;
                            break;
                        default:
                            return SEM_ERROR;
                    }
                    return SEM_OK;
            }
            break;
    }
    return SEM_ERROR;
}

static Sem_State ac_sem_push_var(Parser *parser) {
    unsigned int p;
    if (!find_var(parser, &p))return SEM_UNDEFINED_VAR_ERROR;
    parser->sem.push_back({MT_VAR, p});
    return SEM_OK;
}

static Sem_State ac_push_func(CState *cs, Sen_Stack *sem, Token *token) {
    FuncInfo f;
    if (!find_func(&token->s, &f))return SEM_UNDEFINED_FUNCTION_ERROR;
    sem->push_back({MT_T});
    FuncState *pre = cs->funcState;
    cs->funcState = new FuncState({pre, f.params, f.params, f.fp, f.t_var_nums});
    return SEM_OK;
}

static Sem_State ac_func_count(CState *cs, Sen_Stack *sem) {
    if (!cs->funcState->count)return SEM_FUNC_PARAM_ERROR;
    cs->funcState->count--;
    unsigned int p;
    if (sem->back().mt != MT_T) {
        switch (sem->back().mt) {
            case MT_VAR:
                if (cs->declare_func)
                    code_ABx(cs, OP_MOV, 0, sem->back().v.p);
                else
                    code_ABx(cs, OP_LOAD_M, 0, sem->back().v.p);
                break;
            case MT_INT_CONST:
                if (find_and_alloc_int(cs, sem->back().v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
                code_ABx(cs, OP_LOAD_I, 0, p);
                break;
            case MT_FLOAT_CONST:
                if (find_and_alloc_float(cs, sem->back().v.f, &p))return SEM_MEM_OVERFLOW_ERROR;
                code_ABx(cs, OP_LOAD_F, 0, p);
                break;
            case MT_BOOL_CONST:
                code_ABx(cs, OP_LOAD_B, 0, sem->back().v.b);
                break;
            case MT_STRING_CONST:
                code_ABx(cs, OP_LOAD_STR, 0, sem->back().v.p);
                break;
            default:
                return SEM_ERROR;
        }
        code_ABx(cs, OP_PUSH, 0, 0);
    }
    sem->pop_back();
    return SEM_OK;
}

static Sem_State ac_func_end(CState *cs, Sen_Stack *sem) {
    if (cs->funcState->count)return SEM_FUNC_PARAM_ERROR;
    //TODO FUNC_END
    code_ABx(cs, OP_MOV, 2, cs->funcState->fp - 1);
    code_ABC(cs, OP_CALL, 2, cs->funcState->params, 0);


    for (unsigned int j = cs->funcState->t_var_nums; j > 0; j--) {
        code_op(cs, OP_POPP);
    }
    for (unsigned int j = cs->funcState->params; j > 0; j--) {
        code_op(cs, OP_POP);
    }
    code_ABx(cs, OP_PUSH, 3, 0);
    code_op(cs, OP_GC);
    FuncState *t = cs->funcState;
    cs->funcState = cs->funcState->pre;
    delete t;
    return SEM_OK;
}

static Sem_State ac_sem_pop(CState *cs, Sen_Stack *sem) {
    if (sem->empty())return SEM_STACK_ERROR;
    sem->pop_back();
    return SEM_OK;
}

static Sem_State ac_pop(CState *cs, Sen_Stack *sem) {
    if (sem->empty())return SEM_STACK_ERROR;
    if (sem->back().mt == MT_T)code_op(cs, OP_POP);
    sem->pop_back();
    return SEM_OK;
}

static Sem_State ac_assign_end(CState *cs, Sen_Stack *sem) {
    return ac_assign(cs, sem);
}

static Sem_State ac_push_assign(CState *cs, Sen_Stack *sem) {
    sem->push_back({MT_ASSIGN});
    return SEM_OK;
}

static Sem_State ac_set_ekind(CState *cs, Token *token) {
    switch (token->type) {
        case TK_INT:
            cs->ekind = EINT;
            break;
        case TK_FLOAT:
            cs->ekind = EFLOAT;
            break;
        case TK_MAT:
            cs->ekind = EMAT;
            break;
        case TK_BOOL:
            cs->ekind = EBOOL;
            break;
        case TK_STRING:
            cs->ekind = ESTRING;
            break;
        default:
            return SEM_ERROR;
    }
    return SEM_OK;
}

static bool find_var(Parser *parser, unsigned int *p) {
    if (parser->cs.declare_func) {
        if (Inner_Var_table.find(parser->current_token.s) != Inner_Var_table.end()) {
            *p = Inner_Var_table[parser->current_token.s];
            return true;
        }
    } else {
        if (Var_table.find(parser->current_token.s) != Var_table.end()) {
            *p = Var_table[parser->current_token.s].p;
            return true;
        }
    }
    return false;
}

static bool find_func(String *vn, FuncInfo *f) {
    if (Func_table.find(*vn) != Func_table.end()) {
        *f = Func_table[*vn];
        return true;
    }
    return false;
}

static bool find_int(Int i, unsigned int *p) {
    if (Int_table.find(i) != Int_table.end()) {
        *p = Int_table[i];
        return true;
    }
    return false;
}

static bool find_float(Float i, unsigned int *p) {
    if (Float_table.find(i) != Float_table.end()) {
        *p = Float_table[i];
        return true;
    }
    return false;
}

static bool find_string(String &vn, unsigned int *p) {
    if (String_table.find(vn) != String_table.end()) {
        *p = String_table[vn];
        return true;
    }
    return false;
}

static Sem_State alloc_var(CState *cs, unsigned int *p) {
    if (cs->vm_mem_p >= YCH_VM_MEM_SIZE)return SEM_MEM_OVERFLOW_ERROR;
    *p = cs->vm_mem_p++;
    return SEM_OK;
}

static Sem_State alloc_int(CState *cs, unsigned int *p) {
    if (cs->vm_int_const_p >= YCH_VM_INT_CONST_SIZE)return SEM_MEM_OVERFLOW_ERROR;
    *p = cs->vm_int_const_p++;
    return SEM_OK;
}

static Sem_State alloc_float(CState *cs, unsigned int *p) {
    if (cs->vm_float_const_p >= YCH_VM_INT_CONST_SIZE)return SEM_MEM_OVERFLOW_ERROR;
    *p = cs->vm_float_const_p++;
    return SEM_OK;
}

static Sem_State alloc_string(CState *cs, unsigned int *p) {
    if (cs->vm_string_const_p >= YCH_VM_STR_CONST_SIZE)return SEM_MEM_OVERFLOW_ERROR;
    *p = cs->vm_string_const_p++;
    return SEM_OK;
}

static Sem_State find_and_alloc_int(CState *cs, Int i, unsigned int *p) {
    if (!find_int(i, p)) {
        if (alloc_int(cs, p) == SEM_MEM_OVERFLOW_ERROR)return SEM_MEM_OVERFLOW_ERROR;
        Int_table[i] = *p;
        VM_INT_CONST[*p] = i;
    }
    return SEM_OK;
}

static Sem_State find_and_alloc_float(CState *cs, Float f, unsigned int *p) {
    if (!find_float(f, p)) {
        if (alloc_float(cs, p) == SEM_MEM_OVERFLOW_ERROR)return SEM_MEM_OVERFLOW_ERROR;
        Float_table[f] = *p;
        VM_FLOAT_CONST[*p] = f;
    }
    return SEM_OK;
}

static Sem_State find_and_alloc_string(CState *cs, String &str, unsigned int *p) {
    if (!find_string(str, p)) {
        if (alloc_string(cs, p) == SEM_MEM_OVERFLOW_ERROR)return SEM_MEM_OVERFLOW_ERROR;
        String_table[str] = *p;
        initString(&VM_STR_CONST[*p], str.c_str());
    }
    return SEM_OK;
}

static Sem_State ac_malloc_var(Parser *parser) {
    unsigned int p, np;
    MInfo m;
    if (find_var(parser, &p)) {
        return SEM_REDECLARATION_VAR_ERROR;
    } else {
        if (!parser->cs.declare_func) {
            if (alloc_var(&parser->cs, &p) == SEM_MEM_OVERFLOW_ERROR)
                return SEM_MEM_OVERFLOW_ERROR;
        }
    }
    switch (parser->cs.ekind) {
        case EINT:
            if (parser->cs.declare_func) {
                Inner_Var_table[parser->current_token.s] = p = parser->cs.func_mem_p++;
                parser->cs.funcInfo->t_var_nums++;
                if (find_and_alloc_int(&parser->cs, 0, &np))return SEM_MEM_OVERFLOW_ERROR;
                code_ABx(&parser->cs, OP_LOAD_I, 6, np);
            } else {
                Var_table[parser->current_token.s] = {Ot_Int, p};
                set_Int(p, 0);
            }
            m.mt = MT_INT_VAR;
            break;
        case EFLOAT:
            if (parser->cs.declare_func) {
                Inner_Var_table[parser->current_token.s] = p = parser->cs.func_mem_p++;
                parser->cs.funcInfo->t_var_nums++;
                if (find_and_alloc_float(&parser->cs, 0, &np))return SEM_MEM_OVERFLOW_ERROR;
                code_ABx(&parser->cs, OP_LOAD_F, 6, np);
            } else {
                Var_table[parser->current_token.s] = {Ot_Float, p};
                set_Float(p, 0);
            }
            m.mt = MT_FLOAT_VAR;
            break;
        case EBOOL:
            if (parser->cs.declare_func) {
                Inner_Var_table[parser->current_token.s] = p = parser->cs.func_mem_p++;
                parser->cs.funcInfo->t_var_nums++;
                code_ABx(&parser->cs, OP_LOAD_B, 6, false);
            } else {
                Var_table[parser->current_token.s] = {Ot_Bool, p};
                set_Bool(p, false);
            }
            m.mt = MT_BOOL_VAR;
            break;
        case EMAT:
            if (parser->cs.declare_func) {
                Inner_Var_table[parser->current_token.s] = p = parser->cs.func_mem_p++;
                parser->cs.funcInfo->t_var_nums++;
            } else {
                Var_table[parser->current_token.s] = {Ot_Mat, p};
                set_Mat(p);
            }
            m.mt = MT_MAT_VAR;
            break;
        case ESTRING:
            if (parser->cs.declare_func) {
                Inner_Var_table[parser->current_token.s] = p = parser->cs.func_mem_p++;
                parser->cs.funcInfo->t_var_nums++;
                code_ABx(&parser->cs, OP_LOAD_STR, 6, 0);
            } else {
                Var_table[parser->current_token.s] = {Ot_String, p};
                set_String(p);
            }
            m.mt = MT_STRING_VAR;
            break;
        default:
            return SEM_ERROR;
    }
    if (parser->cs.declare_func)
        code_ABx(&parser->cs, OP_PUSH, 6, 0);
    m.v.p = p;
    parser->sem.push_back(m);
    return SEM_OK;
}

static Sem_State ac_push_const(CState *cs, Sen_Stack *sem, Token *token) {
    MInfo m;
    unsigned int p;
    switch (token->type) {
        case TK_INT_V:
            m.mt = MT_INT_CONST;
            m.v.i = token->n.i;
            break;
        case TK_FLOAT_V:
            m.mt = MT_FLOAT_CONST;
            m.v.f = token->n.f;
            break;
        case TK_TRUE:
            m.mt = MT_BOOL_CONST;
            m.v.b = true;
            break;
        case TK_FALSE:
            m.mt = MT_BOOL_CONST;
            m.v.b = false;
            break;
        case TK_STRING_V://TODO TK_STRING_V
            m.mt = MT_STRING_CONST;
            if (find_and_alloc_string(cs, token->s, &p))return SEM_MEM_OVERFLOW_ERROR;
            m.v.p = p;
            break;
        default:
            return SEM_ERROR;
    }
    sem->push_back(m);
    return SEM_OK;
}

static void set_Int(unsigned int mp, Int i) {
    VM_MEM[mp].t = Ot_Int;
    VM_MEM[mp].v.i = i;
}

static void set_Float(unsigned int mp, Float f) {
    VM_MEM[mp].t = Ot_Float;
    VM_MEM[mp].v.f = f;
}

static void set_Bool(unsigned int mp, bool b) {
    VM_MEM[mp].t = Ot_Bool;
    VM_MEM[mp].v.b = b;
}

static void set_Mat(unsigned int mp) {
    VM_MEM[mp].t = Ot_Mat;
    VM_MEM[mp].v.mat = new Mat({0, 0, nullptr});
}

static void set_String(unsigned int mp) {
    VM_MEM[mp].t = Ot_String;
    VM_MEM[mp].v.str = &VM_STR_CONST[0];
}

static Sem_State gen_assign_first_code(CState *cs, Sen_Stack *sem) {
    unsigned int p;
    MInfo m2 = sem->back();
    sem->pop_back();
    if (m2.mt == MT_MAT_VAR)return SEM_OK;
    MInfo m1 = sem->back();
    sem->pop_back();
    if (m2.mt == MT_VAR) {//TODO FS
        if (cs->declare_func) {
            code_ABx(cs, OP_MOV, 1, m2.v.p);
        } else {
            code_ABx(cs, OP_LOAD_M, 0, m2.v.p);
        }
        code_ABx(cs, OP_STORE_M, cs->declare_func, m1.v.p);
        return SEM_OK;
    } else if (m2.mt == MT_T) {
        code_ABx(cs, OP_LOAD_S, 0, 0);
        code_ABx(cs, OP_STORE_M, cs->declare_func, m1.v.p);
        return SEM_OK;
    }
    if (cs->declare_func) {
        switch (m2.mt) {
            case MT_INT_CONST:
                if (find_and_alloc_int(cs, m2.v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
                code_ABx(cs, OP_LOAD_I, cs->declare_func, p);
                break;
            case MT_FLOAT_CONST:
                if (find_and_alloc_float(cs, m2.v.f, &p))return SEM_MEM_OVERFLOW_ERROR;
                code_ABx(cs, OP_LOAD_F, cs->declare_func, p);
                break;
            case MT_BOOL_CONST:
                code_ABx(cs, OP_LOAD_B, cs->declare_func, m2.v.b);
                break;
            case MT_STRING_CONST:
                code_ABx(cs, OP_LOAD_STR, cs->declare_func, m2.v.p);
                break;
            default:
                return SEM_ERROR;
        }
        code_ABx(cs, OP_STORE_M, cs->declare_func, m1.v.p);
        return SEM_OK;
    } else {
        switch (m1.mt) {
            case MT_INT_VAR:
                switch (m2.mt) {
                    case MT_INT_CONST:
                        set_Int(m1.v.p, m2.v.i);
                        return SEM_OK;
                    case MT_FLOAT_CONST:
                        set_Int(m1.v.p, m2.v.f);
                        return SEM_OK;
                    default:
                        return SEM_ERROR;
                }
            case MT_FLOAT_VAR:
                switch (m2.mt) {
                    case MT_INT_CONST:
                        set_Float(m1.v.p, m2.v.i);
                        return SEM_OK;
                    case MT_FLOAT_CONST:
                        set_Float(m1.v.p, m2.v.f);
                        return SEM_OK;
                    default:
                        return SEM_ERROR;
                }
            case MT_BOOL_VAR:
                switch (m2.mt) {
                    case MT_BOOL_CONST:
                        set_Bool(m1.v.p, m2.v.b);
                        return SEM_OK;
                    default:
                        return SEM_ERROR;
                }
            case MT_STRING_VAR:
                switch (m2.mt) {
                    case MT_STRING_CONST:
                        code_ABx(cs, OP_LOAD_STR, 0, m2.v.p);
                        code_ABx(cs, OP_STORE_M, 0, m1.v.p);
                        return SEM_OK;
                    default:
                        return SEM_ERROR;
                }
        }
    }
    return SEM_ERROR;
}

static Sem_State ac_push_while(CState *cs, Sen_Stack *sem) {
    WhileEvn *pre = cs->whileEvn;
    cs->whileEvn = new WhileEvn();
    cs->whileEvn->pre = pre;
    if (cs->declare_func) {
        sem->push_back({MT_WP, cs->vm_i_f_p});
    } else {
        sem->push_back({MT_WP, cs->vm_i_p});
    }
    return SEM_OK;
}

static Sem_State ac_judge(CState *cs, Sen_Stack *sem, Sen_Stack *if_sem, bool b) {
    MInfo m = sem->back();
    sem->pop_back();
    if (m.mt == MT_T)
        code_ABx(cs, OP_LOAD_S, 0, 0);
    else if (m.mt == MT_BOOL_CONST)
        code_ABx(cs, OP_LOAD_B, 0, m.v.b);
    else if (m.mt == MT_VAR) {
        if (cs->declare_func) {
            code_ABx(cs, OP_MOV, 0, m.v.p);
        } else {
            code_ABx(cs, OP_LOAD_M, 0, m.v.p);
        }
    } else
        return SEM_ERROR;
    if (b) {
        if (cs->declare_func) {
            if_sem->push_back({MT_IP, cs->vm_i_f_p});
        } else {
            if_sem->push_back({MT_IP, cs->vm_i_p});
        }
    } else {
        if (cs->declare_func) {
            sem->push_back({MT_IP, cs->vm_i_f_p});
        } else {
            sem->push_back({MT_IP, cs->vm_i_p});
        }
    }
    code_op(cs, OP_CJUMPF);
    return SEM_OK;
}

static Sem_State ac_while_end(CState *cs, Sen_Stack *sem) {
    MInfo m = sem->back();
    sem->pop_back();
    unsigned p;
    if (cs->declare_func) {
        p = cs->vm_i_f_p;
    } else {
        p = cs->vm_i_p;
    }
    while (m.mt == MT_IP) {
        SET_ARG_Bx(VM_I[m.v.p], (p - m.v.p));
        m = sem->back();
        sem->pop_back();
    }
    code_ABx(cs, OP_JUMP, 0, p + 1 - m.v.p);
    WhileEvn *t = cs->whileEvn;
    cs->whileEvn = cs->whileEvn->pre;
    delete t;
    return SEM_OK;
}

static Sem_State ac_while_break(CState *cs, Sen_Stack *sem) {
    if (!cs->whileEvn) return SEM_BREAK_NOT_IN_LOOP_STRUCT_ERROR;
    if (cs->declare_func) {
        sem->push_back({MT_IP, cs->vm_i_f_p});
    } else {
        sem->push_back({MT_IP, cs->vm_i_p});
    }
    code_ABx(cs, OP_JUMP, 1, 0);
    return SEM_OK;
}

static Sem_State ac_if_end(CState *cs, Sen_Stack *if_sem) {
    MInfo m = if_sem->back();
    if (cs->declare_func) {
        SET_ARG_Bx(VM_I[m.v.p], (cs->vm_i_f_p - m.v.p - 1));
    } else {
        SET_ARG_Bx(VM_I[m.v.p], (cs->vm_i_p - m.v.p - 1));
    }
    if_sem->pop_back();
    return SEM_OK;
}

static Sem_State ac_push_else(CState *cs, Sen_Stack *if_sem) {
    if (cs->declare_func) {
        if_sem->push_back({MT_IP, cs->vm_i_f_p});
    } else {
        if_sem->push_back({MT_IP, cs->vm_i_p});
    }
    code_ABx(cs, OP_JUMP, 1, 0);
    return SEM_OK;
}

static Sem_State ac_else_end(CState *cs, Sen_Stack *if_sem) {
    MInfo m = if_sem->back();
    unsigned int p = m.v.p;
    if (cs->declare_func) {
        SET_ARG_Bx(VM_I[p], (cs->vm_i_f_p - p - 1));
    } else {
        SET_ARG_Bx(VM_I[p], (cs->vm_i_p - p - 1));
    }
    if_sem->pop_back();
    m = if_sem->back();
    SET_ARG_Bx(VM_I[m.v.p], (p - m.v.p));
    if_sem->pop_back();
    return SEM_OK;
}

void load_Clib(CState *cs) {
    cs->declare_func = true;
    for (int i = CFuncSIZE - 1; i >= 0; i--) {
        Func_table[CFuncInfos[i].func_name] = {CFuncInfos[i].params, cs->vm_i_f_p, 0};

        code_ABx(cs, OP_CALL_C, CFuncInfos[i].cft, cs->vm_c_func_p);

        VM_C_FUNC[cs->vm_c_func_p++] = CFuncInfos[i].func_p;

        code_ABx(cs, OP_MOV, 3, 0);

        code_op(cs, OP_LEV);
    }
    cs->declare_func = false;
}

static Sem_State ac_def_func_start(CState *cs, Sen_Stack *sem, Token *token) {
    if (cs->declare_func)return SEM_ERROR;
    cs->declare_func = true;
    if (Func_table.find(token->s) != Func_table.end()) return SEM_REDEF_FUNC_ERROR;
    cs->funcInfo = &Func_table[token->s];
    cs->funcInfo->fp = cs->vm_i_f_p;
    return SEM_OK;
}

static Sem_State ac_def_count_params(Parser *parser) {
    unsigned int p;
    parser->cs.funcInfo->params++;
    if (find_var(parser, &p)) { return SEM_REDECLARATION_VAR_ERROR; }
    else {
        Inner_Var_table[parser->current_token.s] = parser->cs.func_mem_p++;
    }
    return SEM_OK;
}

static Sem_State ac_return(CState *cs, Sen_Stack *sem) {
    if (!cs->declare_func)return SEM_ERROR;
    unsigned int p;
    if (sem->empty()) {
        code_ABx(cs, OP_MOV, 7, 0);
        return SEM_OK;
    }
    if (sem->back().mt != MT_T) {
        switch (sem->back().mt) {
            case MT_VAR:
                code_ABx(cs, OP_MOV, 0, sem->back().v.p);
                break;
            case MT_INT_CONST:
                if (find_and_alloc_int(cs, sem->back().v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
                code_ABx(cs, OP_LOAD_I, 0, p);
                break;
            case MT_FLOAT_CONST:
                if (find_and_alloc_float(cs, sem->back().v.f, &p))return SEM_MEM_OVERFLOW_ERROR;
                code_ABx(cs, OP_LOAD_F, 0, p);
                break;
            case MT_BOOL_CONST:
                code_ABx(cs, OP_LOAD_B, 0, sem->back().v.b);
                break;
            default:
                return SEM_ERROR;
        }
        code_ABx(cs, OP_PUSH, 0, 0);
    }
    sem->pop_back();
    code_ABx(cs, OP_MOV, 3, 0);
    code_op(cs, OP_LEV);
    return SEM_OK;
}


static Sem_State ac_def_func_end(CState *cs, Sen_Stack *sem) {
    code_op(cs, OP_LEV);
    {
        cs->declare_func = false;
        cs->funcInfo = nullptr;
        Inner_Var_table.clear();
        cs->func_mem_p = 0;
    }
    return SEM_OK;
}

static Sem_State ac_mat_count_row(Parser *parser) {
    parser->cs.matState.row++;
    if (parser->cs.matState.t_col > parser->cs.matState.col)
        parser->cs.matState.col = parser->cs.matState.t_col;
    parser->cs.matState.t_col = 0;
    return SEM_OK;
}

static Sem_State ac_mat_count_col(Parser *parser) {
    MInfo m;
    unsigned int p;

    m = parser->sem.back();
    parser->sem.pop_back();
    switch (m.mt) {
        case MT_VAR:
            code_ABx(&parser->cs, OP_LOAD_M, 0, m.v.p);
            break;
        case MT_T:
            code_ABx(&parser->cs, OP_LOAD_S, 0, 0);
            break;
        case MT_INT_CONST:
            if (find_and_alloc_int(&parser->cs, m.v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
            code_ABx(&parser->cs, OP_LOAD_I, 0, p);
            break;
        case MT_FLOAT_CONST:
            if (find_and_alloc_float(&parser->cs, m.v.f, &p))return SEM_MEM_OVERFLOW_ERROR;
            code_ABx(&parser->cs, OP_LOAD_F, 0, p);
            break;
    }
    code_ABC(&parser->cs, OP_MOV, 4, parser->cs.matState.row, parser->cs.matState.t_col);
    code_ABx(&parser->cs, OP_MOV, 5 + parser->cs.declare_func, parser->sem.back().v.p);
    parser->cs.matState.t_col++;
    return SEM_OK;
}

static Sem_State ac_mat_start(Parser *parser) {
    if (parser->sem.back().mt != MT_MAT_VAR)return SEM_ERROR;
    if (parser->cs.declare_func) {
        parser->cs.matState.mat_malloc_p = parser->cs.vm_i_f_p;
    } else {
        parser->cs.matState.mat_malloc_p = parser->cs.vm_i_p;
    }
    code_ABC(&parser->cs, OP_MOV, 4, 0, 0);
    code_ABx(&parser->cs, OP_MALLOC_MAT, parser->cs.declare_func, parser->sem.back().v.p);
    return SEM_OK;
}

static Sem_State ac_mat_end(Parser *parser) {
    SET_ARG_B(VM_I[parser->cs.matState.mat_malloc_p], parser->cs.matState.row);
    SET_ARG_C(VM_I[parser->cs.matState.mat_malloc_p], parser->cs.matState.col);
    return SEM_OK;
}

static Sem_State ac_index(Parser *parser) {
    unsigned int p;
    MInfo m2 = parser->sem.back();
    parser->sem.pop_back();
    MInfo &m1 = parser->sem.back();
    if (m1.mt == MT_VAR) {
        if (parser->cs.declare_func) {
            code_ABx(&parser->cs, OP_MOV, 0, m1.v.p);
        } else {
            code_ABx(&parser->cs, OP_LOAD_M, 0, m1.v.p);
        }
    } else if (m1.mt == MT_T) {
        code_ABx(&parser->cs, OP_LOAD_S, 0, 0);
    } else {
        return SEM_ERROR;
    }
    switch (m2.mt) {
        case MT_VAR:
            if (parser->cs.declare_func) {
                code_ABx(&parser->cs, OP_MOV, 1, m2.v.p);
            } else {
                code_ABx(&parser->cs, OP_LOAD_M, 1, m2.v.p);
            }
            break;
        case MT_T:
            code_ABx(&parser->cs, OP_LOAD_S, 1, 0);
            break;
        case MT_INT_CONST:
            if (find_and_alloc_int(&parser->cs, m2.v.i, &p))return SEM_MEM_OVERFLOW_ERROR;
            code_ABx(&parser->cs, OP_LOAD_I, 1, p);
            break;
        default:
            return SEM_ERROR;
    }
    code_ABC(&parser->cs, OP_INDEX, 0, 0, 1);
    m1.mt = MT_T;
    return SEM_OK;
}